
#include <BReadWrite>
#include <BStyle>
#include "member_BStyle.h"

using namespace BWE;

#define member						(*(member_BStyle*)_ptr)
#define member_allocate()			_ptr = new member_BStyle(this)
#define member_release()			delete (member_BStyle*)_ptr

BColor TextToColor(const BString& text)
{
	BColor color;
	BStringList words = text.split(',');
	color.r() = words(0).toInt();
	color.g() = words(1).toInt();
	color.b() = words(2).toInt();
	color.a() = words(3).toInt();
	return color;
}
BString ColorToText(const BColor& color)
{
	BString text;
	text << color.r() << ',';
	text << color.g() << ',';
	text << color.b() << ',';
	text << color.a();
	return text;
}

BStyle::BStyle()
{
	member_allocate();
}
BStyle::BStyle(const BColor& color)
{
	member_allocate();

	setColor(Value_Title, color % 67);

	BColor closeColor(180, 66, 0);
	setColor(Color_Title_Button, closeColor);
	setColor(Color_Title_Button_Hovered, closeColor % 120);
	setColor(Color_Title_Button_Pressed, closeColor % 80);

	setColor(Value_Border, color % 50);
	setColor(Color_Perch, color % 80);

	int gray = color.gray();
	if (gray > 100)
	{
		setColor(Color_Background, color % 89);
		setColor(Color_Background_Hovered, color % 76);
		setColor(Color_Background_Pressed, color % 60);
		setColor(Color_Background_Checked, color % 66);

		BColor textColor(0, 0, 0);
		setColor(Color_Text, textColor);
		setColor(Color_LineNumber_Text, textColor);
		setColor(Color_Title_Text, textColor);
		setColor(Color_Indicator, textColor % 96);

		setColor(Color_Text_Disable, 99, 99, 99);
		setColor(Color_Text_Hovered, 20, 20, 20);
		setColor(Color_Text_Pressed, 0, 0, 0);
		setColor(Color_Text_Checked, 255, 255, 255);

		setColor(Color_Handle, color % 72);
		setColor(Color_Handle_Hovered, color % 66);
		setColor(Color_Handle_Pressed, color % 56);
		setColor(Color_Handle_Disable, color % 52);

		setColor(Color_Arrow, color % 10);
		setColor(Color_Arrow_Hovered, color % 28);
		setColor(Color_Arrow_Pressed, color % 15);

		setColor(Color_Tab, color % 69);
		setColor(Color_Tab_Hovered, color % 86);
		setColor(Color_Tab_Pressed, color % 36);
		setColor(Color_Tab_Checked, color % 56);

		setColor(Color_Item, color % 69);
		setColor(Color_Item_Hovered, color % 76);
		setColor(Color_Item_Pressed, color % 56);
		setColor(Color_Item_Selected, color % 66);

		setColor(Color_Prefix, textColor);
		setColor(Color_Suffix, textColor);
		setColor(Color_Separator, color % 90);
		setColor(Color_Grid_Ver, color % 62);
		setColor(Color_Grid_Hor, color % 62);
		setColor(Color_Group_Line, color % 62);	

	}
	else
	{
		BColor baseColor = color;
		baseColor.reverse();
		setColor(Color_Background, baseColor % 10);
		setColor(Color_Background_Hovered, baseColor % 26);
		setColor(Color_Background_Pressed, baseColor % 16);
		setColor(Color_Background_Checked, baseColor % 36);

		BColor textColor(255, 255, 255);
		setColor(Color_Text, textColor % 96);
		setColor(Color_LineNumber_Text, textColor);
		setColor(Color_Title_Text, textColor % 96);
		setColor(Color_Text_Disable, textColor % 70);
		setColor(Color_Text_Hovered, textColor % 86);
		setColor(Color_Text_Pressed, textColor);
		setColor(Color_Text_Checked, textColor);
		setColor(Color_Indicator, textColor);

		BColor handlerColor = color;
		handlerColor.reverse();
		setColor(Color_Handle, handlerColor % 33);
		setColor(Color_Handle_Hovered, handlerColor % 46);
		setColor(Color_Handle_Pressed, handlerColor % 36);
		setColor(Color_Handle_Disable, handlerColor % 16);

		BColor arrowColor = color;;
		arrowColor.reverse();
		setColor(Color_Arrow, arrowColor % 66);
		setColor(Color_Arrow_Hovered, arrowColor % 86);
		setColor(Color_Arrow_Pressed, arrowColor % 56);

		BColor tabColor = color;
		tabColor.reverse();
		setColor(Color_Tab, tabColor % 33);
		setColor(Color_Tab_Hovered, tabColor % 28);
		setColor(Color_Tab_Pressed, tabColor % 18);
		setColor(Color_Tab_Checked, tabColor % 25);

		BColor itemColor = color;
		itemColor.reverse();
		setColor(Color_Item, itemColor % 16);
		setColor(Color_Item_Hovered, itemColor % 36);
		setColor(Color_Item_Pressed, itemColor % 16);
		setColor(Color_Item_Selected, itemColor % 26);

		BColor gridColor = color;
		gridColor.reverse();
		setColor(Color_Prefix, textColor);
		setColor(Color_Suffix, textColor);
		setColor(Color_Separator, gridColor);
		setColor(Color_Grid_Ver, gridColor % 86);
		setColor(Color_Grid_Hor, gridColor % 86);
		setColor(Color_Group_Line, gridColor % 86);
	}

}
BStyle::BStyle(const BStyle& other)
{
	member_allocate();
	member.colorMap = style_member(&other)->colorMap;
}

void BStyle::setFont(BFont* font)
{
	member.font = font;
}
const BFont* BStyle::font() const
{
	const BStyle* style = this;
	while (style)
	{
		if (style_member(style)->font)
			return style_member(style)->font;
		style = style_member(style)->lower;
	}
	return 0;
}

void BStyle::setValue(StyleRole valueRole, const BValue& value)
{
	if (valueRole < 1)
		return;
	member.valueMap[valueRole] = value;
}
bool BStyle::removeVlaue(StyleRole valueRole)
{
	return member.valueMap.remove(valueRole);
}
const BValue& BStyle::value(StyleRole valueRole) const
{
	if (valueRole > 0)
		return member.valueMap(valueRole);
	return member.valueMap.def();
}

bool BStyle::setColor(StyleRole colorRole, BByte r, BByte g, BByte b, BByte a)
{
	if (colorRole < 1)
		return false;
	member.colorMap[colorRole].set(r, g, b, a);
	return true;
}
bool BStyle::setColor(StyleRole colorRole, const BColor& color)
{
	if (colorRole < 1)
		return false;
	member.colorMap[colorRole] = color;
	member.dirty = true;
	return true;
}
bool BStyle::removeColor(StyleRole colorRole)
{
	if (member.colorMap.remove(colorRole))
	{
		return true;
	}
	return false;
}
const BColor& BStyle::color(StyleRole colorRole) const
{
	const BStyle* style = this;
	while (style)
	{
		auto it = style_member(style)->colorMap.seek(colorRole);
		if (it.valid())
			return *it;
		style = style_member(style)->lower;
	}
	return member.colorMap.def();
}

bool BStyle::setImage(StyleRole imageRole, const BString& fileName)
{
	if (imageRole < 1)
		return false;
	BImage* image = Read<BImage>(fileName);
	if (image)
	{
		member.imageMap[imageRole] = image;
		return true;
	}
	return false;
}
bool BStyle::setImage(StyleRole imageRole, BImage* image)
{
	if (imageRole < 1)
		return false;
	member.imageMap[imageRole] = image;
	return true;
}
bool BStyle::removeImage(StyleRole imageRole)
{
	return member.imageMap.remove(imageRole);
}
BImage* BStyle::image(StyleRole imageRole) const
{
	const BStyle* style = this;
	while (style)
	{
		auto it = style_member(style)->imageMap.seek(imageRole);
		if (it.valid())
			return *it;
		style = style_member(style)->lower;
	}
	return member.imageMap.def();
}

bool BStyle::setIcon(StyleRole iconRole, const BString& fileName)
{
	if (iconRole < 1)
		return false;
	BIcon* icon = new BIcon(fileName);
	member.iconMap[iconRole] = icon;
	return true;
}
bool BStyle::setIcon(StyleRole iconRole, BIcon* icon)
{
	if (iconRole < 1)
		return false;
	member.iconMap[iconRole] = icon;
	return true;

}
BIcon* BStyle::icon(StyleRole iconRole) const
{
	const BStyle* style = this;
	while (style)
	{
		auto it = style_member(style)->iconMap.seek(iconRole);
		if (it.valid())
			return *it;
		style = style_member(style)->lower;
	}
	return member.iconMap.def();
	return 0;
}

bool BStyle::setTrans(const BString& word, const BString& trans)
{
	if (word.empty())
		return false;
	member.transMap[word] = trans;
	return true;
}
bool BStyle::removeTrans(const BString& word)
{
	return member.transMap.remove(word);
}
bool BStyle::trans(const BString& text, BString& output) const
{
	output.reset();
	BString word;
	int pos = 0;
	while (pos < text.size())
	{
		while (pos < text.size())
		{
			char code = text[pos];
			if (code > 0 && isalpha(text[pos]))
				break;
			output.append(text[pos]);
			pos++;
		}
		int end = pos;
		while (end < text.size())
		{
			char code = text[end];
			if (code > 0 && !isalpha(text[end]))
				break;
			end++;
		}
		if (end > pos)
		{
			word.reset(text, pos, end);
			word.lower();
			const BString& tw = member.transWord(word);
			if (tw.size())
			{
				output.trimmed();
				output << tw;
			}
			else
				output.append(text.cstr() + pos, end - pos);
			pos = end;
		}
	}
	return output.size();
}

bool BStyle::setColor(const BString& colorName, BByte r, BByte g, BByte b, BByte a)
{
	if (colorName.empty())
		return false;
	member.namedColorMap[colorName].set(r, g, b, a);
	return true;
}
bool BStyle::setColor(const BString& colorName, const BColor& color)
{
	if (colorName.empty())
		return false;
	member.namedColorMap[colorName] = color;
	return true;
}
bool BStyle::removeColor(const BString& colorName)
{
	return member.namedColorMap.remove(colorName);
}
const BColor& BStyle::color(const BString& colorName) const
{
	const BStyle* style = this;
	while (style)
	{
		auto it = style_member(style)->namedColorMap.seek(colorName);
		if (it.valid())
			return *it;
		style = style_member(style)->lower;
	}
	return member.namedColorMap.def();
}

bool BStyle::setImage(const BString& imageName, const BString& fileName)
{
	if (imageName.empty())
		return false;
	BImage* image = Read<BImage>(fileName);
	if (image)
	{
		member.namedImageMap[imageName] = image;
		return true;
	}
	return false;
}
bool BStyle::setImage(const BString& imageName, BImage* image)
{
	if (image)
	{
		member.namedImageMap[imageName] = image;
		return true;
	}
	return false;
}
bool BStyle::removeImage(const BString& imageName)
{
	return member.namedImageMap.remove(imageName);
}
BImage* BStyle::image(const BString& name) const
{
	const BStyle* style = this;
	while (style)
	{
		auto it = style_member(style)->namedImageMap.seek(name);
		if (it.valid())
			return *it;
		style = style_member(style)->lower;
	}
	return member.namedImageMap.def();
}

bool BStyle::setIcon(const BString& iconName, const BString& fileName)
{
	if (iconName.empty())
		return false;
	BIcon* icon = new BIcon(fileName);
	member.namedIconMap[iconName] = icon;
	return true;
}
bool BStyle::setIcon(const BString& iconName, BIcon* icon)
{
	if (icon)
	{
		member.namedIconMap[iconName] = icon;
		return true;
	}
	return false;
}
bool BStyle::removeIcon(const BString& iconName)
{
	return member.namedIconMap.remove(iconName);
}
BIcon* BStyle::icon(const BString& name) const
{
	const BStyle* style = this;
	while (style)
	{
		auto it = style_member(style)->namedIconMap.seek(name);
		if (it.valid())
			return *it;
		style = style_member(style)->lower;
	}
	return member.namedIconMap.def();
}

bool BStyle::clearColors()
{
	member.colorMap.clear();
	member.namedColorMap.clear();
	return true;
}
void BStyle::clearImages()
{
	member.imageMap.clear();
	member.namedImageMap.clear();
}
void BStyle::clearIcons()
{
	member.iconMap.clear();
	member.namedIconMap.clear();

}
